#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <cmath>
#include <crtdefs.h>
#include <cstdlib>
#include <ctime>

// Optical system metrics
static double pixe_angl;

// State machine
static int state = 0;
static int internal_state = 0;
static double timer = 0;
static double wait_time = 0;

// Testing parameters / gabor
const double gabo_min_wave_leng = 0.00145444104; // 12 cycles per degree
const double gabo_max_wave_leng = 0.01163552833; // 1.5 cycles per degree
static int reps;
static double start_size_normalized;
static int size_prog;
static int difficulty;
// Dynamic
static double gabo_wave_leng;
static double ampli;
static int gabo_wave_leng_pix;
static double orientation;
static double* gabor;
static double* flanker1;
static double* flanker2;
static int separation;
static bool gabor_first;

int GaborPatch(double* array, double ampli, double orientation, int wave_leng)
{
	delete[] array;
	int size = 2 * wave_leng;
	double cosi_fact = 2 * 3.141593 / wave_leng;
	array = new double[size * size];
	for (int y = 0; y < size; y++)
	  for (int x = 0; x < size; x++)
	  {
		 double xtick = (double(x) - size/2) * cos(orientation) + (double(y) - size/2) * sin(orientation);
		 int arrInd = x + y * size;
		 array[arrInd] = ampli * cos(cosi_fact * xtick/size) + 0.5;
	  }
	return size;
}

int config_lookup_line(FILE* file, char* lookup, int* deci_numb)
{
	static int err = 0;
	static char buffer[256];
	int num_errors;
	while (fgets(buffer, 256, file) != NULL)
		if(strstr(buffer, lookup) != NULL)
			break;
	rewind(file);
	if (sscanf(buffer, strcat(lookup, " = %d"), deci_numb) != 1)
		err += 1;
	else
		return err;
}

int config_lookup_line(FILE* file, char* lookup, double* floater)
{
	static int err = 0;
	static char buffer[256];
	int num_errors;
	while (fgets(buffer, 256, file) != NULL)
		if(strstr(buffer, lookup) != NULL)
			break;
	rewind(file);
	if (sscanf(buffer, strcat(lookup, " = %Lf"), floater) != 1)
		err += 1;
	else
		return err;
}

int sys_initialize()
{
	int errors = 0;
	FILE* cfg_file = fopen("USER.cfg", "r");

	double scre_size;
	int scre_res_x;
	int scre_res_y;
	double scre_view_dist;

	errors += config_lookup_line(cfg_file, "screen_size", &scre_size);
	errors += config_lookup_line(cfg_file, "resolution_x", &scre_res_x);
	errors += config_lookup_line(cfg_file, "resolution_y", &scre_res_y);
	errors += config_lookup_line(cfg_file, "view_distance", &scre_view_dist);
	pixe_angl = atan( ( scre_size / scre_res_x ) / scre_view_dist);
	errors += config_lookup_line(cfg_file, "normalized_init_size", &start_size_normalized);
	gabo_wave_leng = gabo_max_wave_leng - 
		start_size_normalized * (gabo_max_wave_leng - gabo_min_wave_leng);
	errors += config_lookup_line(cfg_file, "size_progression", &size_prog);
	errors += config_lookup_line(cfg_file, "reps_to_min_size", &reps);
	errors += config_lookup_line(cfg_file, "difficulty", &difficulty);
	ampli = 0.2 * ( (100 - difficulty) / 100 );
	grap_init_2d_alpha();

	return errors;
}

int sys_loop(double delta_time)
{
	switch (state)
	{
	case 0:
		srand(clock());
		gabo_wave_leng_pix = gabo_wave_leng / pixe_angl;
		orientation = (rand() % 3142)/1000;
		GaborPatch(gabor, ampli, orientation, gabo_wave_leng_pix);
		GaborPatch(flanker1, 0.5, orientation, gabo_wave_leng_pix);
		GaborPatch(flanker2, 0.5, orientation, gabo_wave_leng_pix);
		++state;
		break;
	case 1:
		switch (internal_state)
		{
		case 0:
			wait_time = 0.5;
			separation = ( double(rand() % (85 * gabo_wave_leng_pix)) / 10 ) 
					+ 1.5 * double(gabo_wave_leng_pix) + 0.5;
			grap_clea_grey();
			++internal_state;
			timer = 0;
			break;
		case 1:
			if ( ( timer += delta_time ) >= wait_time )
			{
				++state;
				timer = 0;
				--internal_state;
			}
			break;
		}
		break;
	case 2:
		if (rand() % 2 == 0)
			gabor_first = true;
		if (gabor_first)
		{

		}
		break;
	case 5:
		switch (internal_state)
		{
		case 0:
			if (size_prog)
				if (gabo_wave_leng >= gabo_min_wave_leng)
					gabo_wave_leng -= (gabo_max_wave_leng - gabo_min_wave_leng) / reps;
			++internal_state;
		case 1:
			if ( ( timer += delta_time ) >= wait_time )
			{

			}
		}
	return 0;
}